package org.slf4j.helpers;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.slf4j.Marker;

public class BasicMarker implements Marker {

	private static final long serialVersionUID = -2849567615646933777L;
	private final String name;
	private List<Marker> referenceList = new CopyOnWriteArrayList<Marker>();

	BasicMarker(String name) {
		if (name == null) {
			throw new IllegalArgumentException("A marker name cannot be null");
		}
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void add(Marker reference) {
		if (reference == null) {
			throw new IllegalArgumentException("A null value cannot be added to a Marker as reference.");
		}

		if (this.contains(reference)) {
			return;

		} else if (reference.contains(this)) {
			return;
		} else {
			referenceList.add(reference);
		}
	}

	public boolean hasReferences() {
		return (referenceList.size() > 0);
	}

	public boolean hasChildren() {
		return hasReferences();
	}

	public Iterator<Marker> iterator() {
		return referenceList.iterator();
	}

	public boolean remove(Marker referenceToRemove) {
		return referenceList.remove(referenceToRemove);
	}

	public boolean contains(Marker other) {
		if (other == null) {
			throw new IllegalArgumentException("Other cannot be null");
		}

		if (this.equals(other)) {
			return true;
		}

		if (hasReferences()) {
			for (Marker ref : referenceList) {
				if (ref.contains(other)) {
					return true;
				}
			}
		}

		return false;
	}

	public boolean contains(String name) {
		if (name == null) {
			throw new IllegalArgumentException("Other cannot be null");
		}

		if (this.name.equals(name)) {
			return true;
		}

		if (hasReferences()) {
			for (Marker ref : referenceList) {
				if (ref.contains(name)) {
					return true;
				}
			}
		}

		return false;
	}

	private static String OPEN = "[ ";
	private static String CLOSE = " ]";
	private static String SEP = ", ";

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Marker))
			return false;

		final Marker other = (Marker) obj;
		return name.equals(other.getName());
	}

	public int hashCode() {
		return name.hashCode();
	}

	public String toString() {
		if (!this.hasReferences()) {
			return this.getName();
		}
		Iterator<Marker> it = this.iterator();
		Marker reference;
		StringBuilder sb = new StringBuilder(this.getName());
		sb.append(' ').append(OPEN);
		while (it.hasNext()) {
			reference = it.next();
			sb.append(reference.getName());
			if (it.hasNext()) {
				sb.append(SEP);
			}
		}
		sb.append(CLOSE);

		return sb.toString();
	}

}
